


#include <stdlib.h>
#include <string.h>
#include <sstream>
#include "door.h"
#include "catdoors.h"
#include "expdoors.h"



using namespace std;



// ExpAllSafe ::



ExpAllSafe::ExpAllSafe( Category *cat, Subject *owner )
    : ExpressionCategory( cat )    
{    
    m_bInverted = !check(owner);
}



ExpAllSafe::ExpAllSafe( Category *cat )
    : ExpressionCategory( cat )
{    
}



Expression *ExpAllSafe::createExpression( Category *cat, Subject *owner )
{
    return new ExpAllSafe(cat, owner);
}



bool ExpAllSafe::check( Subject *owner ) const
{
    const CollectionSubjects &doors = m_pCategory->getSubjects(owner);
    CollectionSubjects::const_iterator id = doors.begin(), id_end = doors.end();
    for( ; id != id_end; ++id )
    {
        Door *door = static_cast <Door*> (*id);
        if( !door->isSafe() )
            return !straight(owner);
    }

    return straight(owner);
}



void ExpAllSafe::putText( ostream &S, Subject *owner, bool invert ) const
{
    if( isInverted() != invert )
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << " is a trap." << endl;
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "At least one of " << m_pCategory->putText(owner) << " is a trap." << endl;
        }
    }
    else
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << " is safe to enter." << endl;
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "All " << m_pCategory->putText(owner) << " are safe to enter." << endl;
        }
    }
}



// ExpAllTraps ::



ExpAllTraps::ExpAllTraps( Category *cat, Subject *owner )
    : ExpAllSafe( cat )
{
    m_bInverted = !check(owner);
}



Expression *ExpAllTraps::createExpression( Category *cat, Subject *owner )
{
    return new ExpAllTraps( cat, owner );
}



bool ExpAllTraps::check( Subject *owner ) const
{
    const CollectionSubjects &doors = m_pCategory->getSubjects(owner);
    CollectionSubjects::const_iterator id = doors.begin(), id_end = doors.end();
    for( ; id != id_end; ++id )
    {
        Door *door = static_cast <Door*> (*id);
        if( door->isSafe() )
            return !straight(owner);
    }

    return straight(owner);
}



void ExpAllTraps::putText( ostream &S, Subject *owner, bool invert ) const
{
    if( isInverted() != invert )
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << " is safe to enter." << endl;
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "At least one of " << m_pCategory->putText(owner) << " is safe to enter." << endl;
        }
    }
    else
    {
        if( m_pCategory->one(owner) )
        {
            ostringstream oss;
            oss << m_pCategory->putText(owner) << " is a trap." << endl;
            capitalize( S, oss.str().c_str() );
        }
        else
        {
            S << "All " << m_pCategory->putText(owner) << " are traps." << endl;
        }
    }
}



// ExpSafeOrTraps ::



ExpSafeOrTraps::ExpSafeOrTraps( Category *cat, Subject *owner )
    : ExpressionCategory( cat )    
{
    m_bInverted = !check(owner);
}



Expression *ExpSafeOrTraps::createExpression( Category *cat, Subject *owner )
{
    if( cat->visible() && cat->one() )
        return NULL;
    else
        return new ExpSafeOrTraps(cat, owner);
}



bool ExpSafeOrTraps::check( Subject *owner ) const
{
    bool bSafe = false, bTrap = false;
    const CollectionSubjects &doors = m_pCategory->getSubjects(owner);
    CollectionSubjects::const_iterator id = doors.begin(), id_end = doors.end();
    if( id == id_end )
        return true;
    
    for( ; id != id_end; ++id )
    {
        Door *door = static_cast <Door*> (*id);
        if( door->isSafe() )
        {
            bSafe = true;
            if( bTrap )
                return straight(owner);
        }
        else
        {
            bTrap = true;
            if( bSafe )
                return straight(owner);
        }
    }
    
    return !straight(owner);    
}



void ExpSafeOrTraps::putText( ostream &S, Subject *owner, bool invert ) const
{
    if( isInverted() != invert )
        S << "Either all " << m_pCategory->putText(owner) << " are traps, or they all are safe to enter." << endl;
    else
        S << "Some of " << m_pCategory->putText(owner) << " are traps, some are safe to enter." << endl;
}
